/*
 * Created by 2019年1月24日
 */
package top.v5it.japi.ddd.core.web;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import org.springframework.web.bind.annotation.*;
import top.v5it.japi.ddd.core.entity.Entity;
import top.v5it.japi.ddd.core.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * The generate controller for CRUD operations by ORM
 *
 * @author fangang
 */
@RestController
public class OrmController extends BaseController {

    /**
     * execute a bean's method by POST method.
     * NOTE: if the method has a value object, it must be the first parameter.
     * The other parameters must name like arg0, arg1, and so on.
     *
     * @param beanName
     * @param methodName
     * @param request
     * @return the returned value of the method
     */
    @RequestMapping(value = "orm/{bean}/{method}", method = {RequestMethod.GET, RequestMethod.POST})
    public Object execute(@PathVariable("bean") String beanName, @PathVariable("method") String methodName,
                          @RequestBody(required = false) Map<String, Object> json, HttpServletRequest request) {
        HttpHeadFactory.INSTANCE.putRequestHeadAll(ServletUtil.getHeaderMap(request));
        Object service = getBean(beanName);
        final String realMethodName = StrUtil.toCamelCase(methodName);
        Method method = getMethod(service, realMethodName);
        json = toMap(json, request);
        Object vo = getValueObj(method, json);
        Object[] args = getArguments(method, json, vo);
        return invoke(service, method, args);
    }

    /**
     * get the first parameter of the method, as the value object, and instance, set values from the json.
     * if the json is null or empty, means no value object, then return null.
     * if there is no parameters of the method, then return null.
     *
     * @param method
     * @param json
     * @return the value object with it's data.
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    private Object getValueObj(Method method, Map<String, Object> json) {
        if (json == null || json.isEmpty()) return null;
        Class<?>[] allOfParameterTypes = method.getParameterTypes();
        if (allOfParameterTypes.length == 0) return null;
        Class<?> firstOfParameterType = allOfParameterTypes[0];
        if (!EntityUtils.isEntity(firstOfParameterType)) return null;
        final Entity entity = EntityUtils.createEntity((Class<Entity>) firstOfParameterType, json);
        validateEntity(entity);
        return entity;
    }
}
